#include "protreethread.h"

#include <QDir>
#include <QDebug>
#include "protreewidgetitem.h"
#include "const.h"

ProTreeThread::ProTreeThread(const QString &src_path, const QString &dest_path,
                             int file_count, QTreeWidgetItem *parent_item,
                             QTreeWidgetItem *root_item, QTreeWidget *self,
                             QObject *parent)
    : QThread(parent),
      _src_path(src_path),
      _dest_path(dest_path),
      _file_count(file_count),
      _parent_item(parent_item),
      _root_item(root_item),
      _self(self),
      _bstop(false)
{

}

ProTreeThread::~ProTreeThread()
{
    ;
}

// 实现copy文件功能和目录树创建
//    (1) 根据文件类型(文件夹还是文件)执行不同的逻辑，
//        如果是文件则创建item添加到父节点下。
//        如果是文件夹类型，则递归进入创建逻辑，直到所有的文件和文件夹被遍历完成。
//    (2) 如果_bstop被设置为true，则退出创建逻辑。
//    (3) 统计文件数，发信号SigUpdateProgress通知进度框更新进度
//    浅谈一下_bstop的设计逻辑。因为QTread类提供了terminate和quit函数，
//    这些只能从机制上保证线程退出，并不能保证逻辑的准确性，所以我并没有采用这个机制，
//    而是通过_bstop的方式从逻辑上控制退出。
//    至于为什么有多处判断，因为创建逻辑是递归方式，为了保证退出的效率所以在多处判断，
//    不加锁也是为了提高程序运行的效率。
//   是将src_path下的内容拷贝到 dest_path 下
//   src_path 是通过文件对话框打开的 目录
//   dest_path 是相册所在的目录
//   parent_item 是上一层节点
void ProTreeThread::CreateProTree(const QString& src_path,const QString& dest_path,int& file_count,
                     QTreeWidgetItem* parent_item, QTreeWidgetItem* root_item,
                     QTreeWidget* self,QTreeWidgetItem* pre_item)
{
    // _bstop是线程外部控制的
    // 当外部有人点击了退出，或者取消加载时_bstop为false
    // 多处判断_bstop是为了提高效率，及时退出
    if(_bstop)
        return;
    bool iscopy = true;
    // 提前判断 图片文件是否需要拷贝， 至于目录 路径相同，但其目录下的内容可能不能所以还是需要遍历
    if(src_path == dest_path)
        iscopy = false;
    QDir import_dir(src_path);
    // 通过打印看看src_path 和 dest_path
    qDebug() << "src_path is " << src_path << "\ndest_path is " << dest_path;
    // 设置文件过滤器
    // QStringList nameFilters;
    // 过滤该目录下的一些文件
    // 只保留 目录和文件， ..和.不要 这个是针对Linux的
    import_dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
    // 该目录下按照名字来排序
    import_dir.setSorting(QDir::Name);
    // 也可以去设置文件名的过滤
    // import_dir.setNameFilters(nameFilters);
    // 根据刚才设置的 setFilter,setSorting来获取该目录下的文件和目录的文件列表
    QFileInfoList list = import_dir.entryInfoList();
    qDebug() << "list.size: " <<  list.size() << endl;
    // 遍历文件列表 根据 元素的类型不同做出对应的动作
    // 如果元素是目录，如果元素是文件
    for(int i = 0; i < list.size();i++)
    {
        if(_bstop)
            return;
        QFileInfo fileInfo = list.at(i);
        bool isDir = fileInfo.isDir();
        // 当是目录的情况下
        if(isDir)
        {
            qDebug() << " 是目录";
            if(_bstop)
                return;
            file_count++;
            // 发出信号通知主线程 文件的数量，让它计时更新进度条
            emit SigUpdateProgress(file_count);
//            qDebug()<< "fileInfo.fileName()" << fileInfo.fileName();
//            qDebug()<< "fileInfo.absoluteFilePath() " << fileInfo.absoluteFilePath();
//            qDebug()<< "fileInfo.absolutePath() " << fileInfo.absolutePath();
            // 当前是目录时，要将这个目录拷贝到相册目录中
            // 因此要构建当前相册所在的目录
            // 在把当前的目录添加到 相册目录后面

            // 获取当前的相册目录
            QDir dest_dir(dest_path);
            // 构建其在 相册目录下的子目录
            QString sub_dest_path = dest_dir.absoluteFilePath(fileInfo.fileName());
            QDir sub_dest_dir(sub_dest_path);
            qDebug() << "sub_dest_dir = " << sub_dest_dir << endl;
            // 如果相册目录下没有该子目录则创建它
            if(!sub_dest_dir.exists())
            {
                // 创建该目录
                bool ok = sub_dest_dir.mkpath(sub_dest_path);
                if(!ok)
                {
                    qDebug() << "sub_dest_dir mkpath failed";
                    // 创建失败则继续下一个 元素
                    continue;
                }
                 qDebug() <<"mkpath successful " << endl;
            }
            // 构建节点 - 节点类型是目录
            auto* item = new ProTreeWidgetItem(parent_item,fileInfo.fileName(),sub_dest_path,root_item,TreeItemDir);
            // 设置该节点属性
            item->setData(0,Qt::DisplayRole,fileInfo.fileName());
            item->setData(0,Qt::DecorationRole,QIcon(":/QIcon/dir.png"));
            item->setData(0,Qt::ToolTipRole,sub_dest_path);

            // 递归调用 进入当前子目录下面，再去创建与打开文件

            // 要去当前目录下的文件夹下面再去找文件 所以得是absoluteFilePath,而不是 absolutePath
            // 文件夹的路径：C:a/a
            // absolutePath: C:a/
            // absoluteFilePath: C:a/a
            CreateProTree(fileInfo.absoluteFilePath(),sub_dest_path,file_count,item,root_item,self,pre_item);


        }
        else // 是普通文件
        {
            qDebug() << " 是文件";
            if(_bstop)
                return;
            const QString& suffix = fileInfo.suffix();
            // 过滤一下文件，我们只需要图片文件
            if(suffix != "png" && suffix != "jpeg" && suffix != "jpg")
            {
                qDebug() << "suffix is not pic" << suffix << endl;
                continue;
            }
            // 更新文件数量
            file_count++;
            // 发生信号，通知主线程更新进度条
            emit SigUpdateProgress(file_count);
            // 已经存在的文件则不拷贝
            if(!iscopy)
                continue;
            // 获取当前的相册目录
            QDir dest_dir(dest_path);
            // 在相册目录下构建 新的文件路径
            QString dest_file_path = dest_dir.absoluteFilePath(fileInfo.fileName());
            // 拷贝
            if(!QFile::copy(fileInfo.absoluteFilePath(),dest_file_path))
            {
                qDebug() << "file src to dest copy failed" << endl;
                continue;
            }
            // 构建新的图片节点
            // 在构造函数中它完成了连接工作
            auto* item = new ProTreeWidgetItem(parent_item,fileInfo.fileName(),dest_file_path,root_item,TreeItemPic);
            item->setData(0,Qt::DisplayRole,fileInfo.fileName());
            item->setData(0,Qt::DecorationRole,QIcon(":/QIcon/pic.png"));
            item->setData(0,Qt::ToolTipRole,dest_file_path);

            // 和前一个节点相互连接

            if(pre_item)
            {
                auto* pre_item_tmp = dynamic_cast<ProTreeWidgetItem*>(pre_item);
                pre_item_tmp->SetNextItem(item);
            }
            item->SetPreItem(pre_item);

            pre_item = item;


        }

    }
    // 设置父亲节点可以展开
    parent_item->setExpanded(true);
}

void ProTreeThread::SlotCancelImport()
{
    _bstop = true;
}


void ProTreeThread::run()
{
    qDebug() << "import thread is running..." << endl;
    // 当主线程点击取消复制后，_bstop = true，CreateProTree 会结束
    CreateProTree(_src_path,_dest_path,_file_count,_parent_item,_root_item,_self,_parent_item);
    // 取消复制，除了要删除界面上的节点还要删除创建目录or文件
    if(_bstop)
    {
        // 当取消复制后，要把创建的根节点移除并且删除文件内文件
        auto path = dynamic_cast<ProTreeWidgetItem*>(_root_item)->GetPath();
        // 返回给定节点 _root_item 的索引
        auto index = _self->indexOfTopLevelItem(_root_item);
        // 移除树中给定索引处的顶级项节点，并返回他
        delete _self->takeTopLevelItem(index);
        QDir dir(path);
        // 删除目录下的所用内容
        dir.removeRecursively();

        return;
    }
    // _file_count 是创建项目中统计的个数
    emit SigFinishProgress(_file_count);
}

